#include <iostream>
#include <string>
#include <stdint.h>
#include <thread>
#include <chrono>

#include <boost/asio.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/bind.hpp>

using boost::asio::ip::tcp;

/// \brief 客户端类
class Client
{
public:
	Client(boost::asio::io_service &io_service, const std::string &ip, uint16_t port):
		m_socket(io_service)
	{
		m_stopped = false;
		m_ip = ip;
		m_port = port;
	}

	/// \brief destruct
	~Client()
	{
		m_stopped = true;
		boost::system::error_code ignored_ec;
		m_socket.close(ignored_ec);
	}

	/// \brief 获取端口
	uint16_t port() {return m_port;}

	/// \brief 获取ip
	const std::string &getIp() {return m_ip;}

	/// \brief 开始
	void start()
	{
		std::cout << "start connect: " << m_ip << ":" << m_port << std::endl;
		startConnect();
	}

private:
	/// \brief 启动连接
	void startConnect()
	{
		tcp::endpoint ep(boost::asio::ip::address::from_string(m_ip), m_port);
		m_socket.async_connect(ep, boost::bind(&Client::handleConnect, this, _1));
	}

	/// \brief 连接回调
	void handleConnect(const boost::system::error_code& ec)
	{
		if (!m_socket.is_open()){
			// 连接超时 更换endpoint_inte
			m_socket.close();
			std::this_thread::sleep_for(std::chrono::seconds(2));
			startConnect();
		}

		if (ec)
		{
			// 判断是否连接失败, 连接失败关闭socket 重新连接
			std::cout << "Connect error: " << ec.message() << "\n";
			m_socket.close();
			std::this_thread::sleep_for(std::chrono::seconds(2));
			startConnect();
		}
		else
		{
			// 连接成功 启动异步读取和心跳
			std::cout << "Connected to " << m_ip << ":" << m_port << "\n";

			// 开始异步读取
			m_socket.async_read_some(boost::asio::buffer(m_buff, 1024), boost::bind(&Client::handleRead, this,::_1, ::_2));
		}
	}

	void handleRead(const boost::system::error_code& error,  uint32_t read_size)
	{
		if (error){
			m_socket.close();
			startConnect();
		}
		else {
			std::string str(m_buff, read_size);
			std::cout << "read:" << str;
			m_socket.async_write_some(boost::asio::buffer("1234", 4),
				boost::bind(&Client::handleWrite, this,
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred));

			// 开始异步读取
			m_socket.async_read_some(boost::asio::buffer(m_buff, 1024), boost::bind(&Client::handleRead, this,::_1, ::_2));
		}
	}

	void handleWrite(const boost::system::error_code& ec,size_t send_size)
	{
		if (ec){
			m_socket.close();
			startConnect();
		}
	}


private:
	char m_buff[1024];
	tcp::socket m_socket;	///< socket
	bool m_stopped;			///< 是否停止
	std::string m_ip;		///< ip
	uint16_t m_port;		///< 端口
};


/// \brief 客户端测试
void testClient()
{
    boost::asio::io_service io_service;
	Client client1(io_service, "127.0.0.1", 15000);
	// Client client2(io_service, "10.9.192.123", 8091);
	client1.start();
	// client2.start();
	io_service.run();
	std::cout << "done testClient \n";
}

/// \brief 结束新号
void handler(const boost::system::error_code &error, int signal_number)
{
    std::cout << "handling signal " << signal_number << std::endl;
    return;
}

int main(int argc, char *argv[])
{
	try {
        boost::asio::io_service io_service;
        boost::asio::signal_set signals(io_service, SIGINT);

		// 测试客户端
		std::thread(testClient).detach();

		// 等待结束信号
        signals.async_wait(handler);
        io_service.run();
	}
	catch(std::exception &e){
        std::cout << "Exception: " << e.what() << "\n";
	}
}
